// ***** BEGIN LICENSE BLOCK *****
// Version: MPL 1.1/GPL 2.0/LGPL 2.1
//
// The contents of this file are subject to the Mozilla Public License Version
// 1.1 (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// The Initial Developer of the Original Code is
//   Axel Nennker http://axel.nennker.de/ .
// Created by the Initial Developer are Copyright (C) 2011
// the Initial Developer. All Rights Reserved.

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/Services.jsm");

var DoIhaveAnOpenID = {
  consoleService : null,
  domains : null,
  
  _logMessage : function _logMessage(message)
  {
//    consoleService = Services.console;
//    Services.console.logStringMessage( "DoIhaveAnOpenID:" + message);
  },

  getDomains : function _getDomains() {
    try {
      var passwordManager = Components.classes["@mozilla.org/login-manager;1"].
        getService(Components.interfaces.nsILoginManager);
      var allLogins = passwordManager.getAllLogins({});
      var emails = {};
      var domains = {};
//      domains["https://auth.services.mozilla.com"] = true;
//      domains["https://services.mozilla.com/openid/"] = true;
//      return [emails, domains];
      for (var i=0; i<allLogins.length;i++) {
        var login = allLogins[i];
        var username = login.username;
        if (login.hostname.indexOf("chrome://") == 0) {
//          DoIhaveAnOpenID._logMessage("login.username=" + login.username + 
//              " login.hostname=" + login.hostname +
//              " login.username=" + login.username +
//              " login.password=" + login.password +
//              " login.httpRealm=" + login.httpRealm +
//              " login.formSubmitURL=" + login.formSubmitURL);
        }
        var split = username.split('@');
        if (split.length == 2) {
          var domain = split[1];
          var emailuser = split[0];
          split = domain.split('.');
          if (split.length > 1) {
//            DoIhaveAnOpenID._logMessage("emailuser=" + emailuser + " domain=" + domain);
            emails[username] = true;
//            domains[domain] = true;
          }
        } else {
          //DoIhaveAnOpenID._logMessage("HOSTNAME=" + login.hostname);
          if (login.hostname.indexOf("file://") === 0) {
          } else {
            if (login.hostname.indexOf("chrome://") === 0) {
            } else {
              domains[login.hostname] = true;
            }
          }
        }
      }
      return [emails, domains];
    } catch(e) {
      Components.utils.reportError(e);
    }
  },
  
  onButtonCommandHandler : function _onButtonCommandHandler(event) {
    var what = event.target.label;
    DoIhaveAnOpenID.onButtonCommand(what);
  },
  
  onButtonCommand : function _onButtonCommand(what) {
    try { 
      var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
        .getInterface(Components.interfaces.nsIWebNavigation)
        .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
        .rootTreeItem
        .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
        .getInterface(Components.interfaces.nsIDOMWindow);
      mainWindow.gBrowser.selectedTab = mainWindow.gBrowser.addTab(what); 
    } catch(e) {
      Components.utils.reportError(e);
    }
  },

  incrementProgressmeter : function _incrementProgressmeter(doc, what) {
//    DoIhaveAnOpenID._logMessage("incrementProgressmeter what=" + what);
    try {
      var progressmeter = doc.getElementById("progressmeter");
      var count = parseInt(progressmeter.getAttribute("value"));
      count = count + 1;
      progressmeter.setAttribute("value", count);
//      DoIhaveAnOpenID._logMessage("incrementProgressmeter count=" + count);
      var label = document.getElementById("label");
      label.setAttribute("value", count);
    } catch(e) {
      Components.utils.reportError(e);
    }
  },

  insertOpenIdButton : function _insertOpenIdButton(doc, what, uri) {
//    DoIhaveAnOpenID._logMessage("insertButton what=" + what);
    try {
      var label;
      if (uri) {
        label = uri;
      } else {
        label = what;
      }
      var domainssElt = document.getElementById("domains");
      var div = document.createElement("button");
      div.setAttribute("class", "domain");
      div.setAttribute("label", label);
      div.setAttribute("id", what);
      div.setAttribute("image", "chrome://openidnascar/content/openid-16x16.gif");
//      div.setAttribute("oncommand", 'DoIhaveAnOpenID.onButtonCommand(\"' + what + '\");');
      div.addEventListener('command', DoIhaveAnOpenID.onButtonCommandHandler, true);
      domainssElt.appendChild(div);
    } catch(e) {
      Components.utils.reportError(e);
    }
  },
  
  removeRequestButtonHandler : function _removeRequestButton(event) {
    var what = event.target.id;
    DoIhaveAnOpenID.removeRequestButton(what, true);
  },
  
  removeRequestButton : function _removeRequestButton(what, cancelB) {
//    DoIhaveAnOpenID._logMessage("removeRequestButton what=" + what);
    try {
      if (DoIhaveAnOpenID.domains[what] === false) return; // already removed it
      if (!cancelB) {
        var progressmeter = document.getElementById("progressmeter");
        var max = parseInt(progressmeter.max);
        var value = 1 + parseInt(progressmeter.value);
//        DoIhaveAnOpenID._logMessage("removeRequestButton max=" + max);
//        DoIhaveAnOpenID._logMessage("removeRequestButton value=" + value);
        if (value >= max) {
          var bundleService = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
          var browserBundle = bundleService.createBundle("chrome://openidnascar/locale/openid.properties");
          var labelvalue = browserBundle.GetStringFromName("openid.done");
          var label = document.getElementById("why");
          label.setAttribute("value", labelvalue);
        }
        DoIhaveAnOpenID.incrementProgressmeter(document, what);
      }
      var elt = document.getElementById(what);
      if (elt) {
        var domainsNode = elt.parentNode;
        domainsNode.removeChild(elt);
      }
      var req = DoIhaveAnOpenID.domains[what];
      if (req) {
        req.abort();
      }
    } catch(e) {
      Components.utils.reportError(e);
    } finally {
      DoIhaveAnOpenID.domains[what] = false;
    }
  },
  
  insertRequestButton : function _insertRequestButton(doc, what) {
//    DoIhaveAnOpenID._logMessage("insertRequestButton what=" + what);
    try {
      var domainssElt = document.getElementById("domains");
      var div = document.createElement("button");
      div.setAttribute("class", "domain");
      div.setAttribute("label", "cancel search for openid at " + what);
      div.setAttribute("id", what);
//      div.setAttribute("oncommand", 'DoIhaveAnOpenID.removeRequestButton(\"' + what + '\", true);');
      div.addEventListener('command', DoIhaveAnOpenID.removeRequestButtonHandler, true);
      domainssElt.appendChild(div);
    } catch(e) {
      Components.utils.reportError(e);
    }
  },
  
  parseXRD : function _parseXRD(doc, what, xrds) {
//    DoIhaveAnOpenID._logMessage("parseXRD xrds=" + xrds);
//    DoIhaveAnOpenID._logMessage("parseXRD typeof(xrds)=" + typeof(xrds));
    try {
      DoIhaveAnOpenID.removeRequestButton(what, false);
      
//      DoIhaveAnOpenID:parseXRD what=<?xml version="1.0" encoding="UTF-8"?>
//      <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
//        <XRD xmlns="xri://$xrd*($v*2.0)" version="2.0">
//          <Service>
//            <Type>http://portablecontacts.net/spec/1.0</Type>
//            <URI>http://www-opensocial.googleusercontent.com/api/people/</URI>
//          </Service>
//          <Service>
//            <Type>http://specs.openid.net/auth/2.0/return_to</Type>
//            <URI>https://www.google.com/accounts</URI>
//          </Service>
//        </XRD>
//      </xrds:XRDS>
      
//      xrds = xrds.replace('<?xml version="1.0" encoding="UTF-8"?>', "");
//      DoIhaveAnOpenID._logMessage("parseXRD XRDS=" + xrds);
      var uri;
      var xrdxml = xrds; // new XML(xrds);
      var elts = xrdxml.getElementsByTagNameNS("xri://$xrd*($v*2.0)", "Service");
//      DoIhaveAnOpenID._logMessage("parseXRD elts.length: " + elts.length);
      for (var i = 0; i < elts.length; i++) {
        var types = elts[i].getElementsByTagNameNS("xri://$xrd*($v*2.0)", "Type");
//        DoIhaveAnOpenID._logMessage("parseXRD types.length: " + types.length);
        if (types.length == 0) {
          continue;
        }
        var type = "" + types[0].firstChild.nodeValue + "";
//        DoIhaveAnOpenID._logMessage("parseXRD type: " + type);
        if (type == "http://specs.openid.net/auth/2.0/return_to") {
          var uris = elts[i].getElementsByTagNameNS("xri://$xrd*($v*2.0)", "URI");
//          DoIhaveAnOpenID._logMessage("parseXRD http://specs.openid.net/auth/2.0/return_to uris.length: " + uris.length);
          if (uris.length == 0) {
            continue;
          }
          uri = "" + uris[0].firstChild.nodeValue + "";
//          DoIhaveAnOpenID._logMessage("parseXRD consumer uri: " + uri);
          DoIhaveAnOpenID.insertOpenIdButton(doc, what, uri);
          return;
        }
//<?xml version="1.0" encoding="UTF-8"?>
//<xrds:XRDS
//    xmlns:xrds="xri://$xrds"
//    xmlns="xri://$xrd*($v*2.0)">
//  <XRD>
//
//    <Service priority="0">
//      <Type>http://specs.openid.net/auth/2.0/server</Type>
//      <Type>http://openid.net/sreg/1.0</Type>
//      <URI priority="0">https://pip.verisignlabs.com/server</URI>
//    </Service>
//
//  </XRD>
//</xrds:XRDS>
        
        if (type == "http://specs.openid.net/auth/2.0/server") {
            var uris = elts[i].getElementsByTagNameNS("xri://$xrd*($v*2.0)", "URI");
//            DoIhaveAnOpenID._logMessage("parseXRD http://specs.openid.net/auth/2.0/ uris.length: " + uris.length);
            if (uris.length == 0) {
              continue;
            }
            uri = "" + uris[0].firstChild.nodeValue + "";
//            DoIhaveAnOpenID._logMessage("parseXRD provider uri: " + uri);
          DoIhaveAnOpenID.insertOpenIdButton(doc, what);
          return;
        }
      }
      
    } catch(e) {
      Components.utils.reportError(e);
    }
  },
  
  handleError : function _handleError(doc, what, req) {
//    DoIhaveAnOpenID._logMessage("handleError what=" + what);
    if (req) {
//      DoIhaveAnOpenID._logMessage("handleError req.status=" + req.status);
//      DoIhaveAnOpenID._logMessage("handleError req.responseText=" + req.responseTex);
    }
    try {
//      var elt = doc.getElementById(what);
//      elt.setAttribute("hidden", "true");
      var req = DoIhaveAnOpenID.domains[what];
      if (req) {
        req.abort();
      }
      DoIhaveAnOpenID.removeRequestButton(what, false);
    } catch(e) {
      Components.utils.reportError(e);
    } finally {
      DoIhaveAnOpenID.domains[what] = null;
    }
  },
  
  getXRD : function _getXRD(doc, what, xrdurl) {
//    DoIhaveAnOpenID._logMessage("getXRD what=" + what);
    try {
      var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
      req.mozBackgroundRequest = true;
      req.open('GET', xrdurl, true);
      req.onreadystatechange = function (aEvt) {
        if (req.readyState == 4) {
           if(req.status == 200) {
//             var respContentType = req.getResponseHeader("Content-Type");
//             DoIhaveAnOpenID._logMessage("getXRD content-type=" + respContentType);
//             DoIhaveAnOpenID._logMessage(req.responseText);
             DoIhaveAnOpenID.parseXRD(doc, what, req.responseXML);
           } else {
//             DoIhaveAnOpenID._logMessage("getXRD Error loading page. Status=" + req.status);
             DoIhaveAnOpenID.handleError(doc, what, req);
           }
        }
      };
      req.setRequestHeader("User-Agent", "xmldap openid stack");
      req.setRequestHeader('Accept', "application/xrds+xml");  
      req.send(null);
    } catch(e) {
      Components.utils.reportError(e);
      DoIhaveAnOpenID.handleError(doc, what);
    }
  },
  
  getYadis : function _getYadis(doc, what) {
//    DoIhaveAnOpenID._logMessage("getYadis what=" + what);
    try {
      var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
      req.mozBackgroundRequest = true;
      req.open('GET', what, true);
      req.onreadystatechange = function (aEvt) {
        if (req.readyState == 4) {
           if(req.status == 200) {
             var yadisLocation = req.getResponseHeader("X-XRDS-Location");
             if (yadisLocation) {
               DoIhaveAnOpenID._logMessage("yadisLocation=" + yadisLocation);
               DoIhaveAnOpenID.getXRD(doc, what, yadisLocation);
             } else {
               //DoIhaveAnOpenID._logMessage(req.responseText);
               DoIhaveAnOpenID.handleError(doc, what, req);
             }
           } else {
             DoIhaveAnOpenID._logMessage("Error loading page. Status=" + req.status);
             DoIhaveAnOpenID.handleError(doc, what, req);
           }
        }
      };
      req.setRequestHeader("User-Agent", "xmldap openid stack");
      req.setRequestHeader('Accept', "application/xrds+xml");
      DoIhaveAnOpenID.insertRequestButton(doc, what);
      DoIhaveAnOpenID.domains[what] = req;
      req.send(null);
    } catch(e) {
      Components.utils.reportError(e);
      DoIhaveAnOpenID.handleError(doc, what);
    }
  },
  
  oncommand : function _oncommand(event) {
    var what= event.target.id;
//    DoIhaveAnOpenID._logMessage("oncommand what=" + what);
    DoIhaveAnOpenID.getYadis(document, what);
  },
  
//  onload : function _onload() {
//    DoIhaveAnOpenID._logMessage("onload start");
//  },
//  
  onload : function _onload() {
//    DoIhaveAnOpenID._logMessage("onload start");
    try {
      var emailsElt = document.getElementById("emails");
      var domainssElt = document.getElementById("domains");
      var progressmeter = document.getElementById("progressmeter");
      var [emails, domains] = DoIhaveAnOpenID.getDomains();
      DoIhaveAnOpenID.domains = domains;
//      for (var prop in emails) {
//        if (emails.hasOwnProperty(prop)) {
//          DoIhaveAnOpenID._logMessage("email=" + prop);
//          try {
//            DoIhaveAnOpenID.getYadis(document, prop);
//          } catch(e) {
//            DoIhaveAnOpenID._logMessage("onload email Exception: " + e);
//          }
//        }
//      }
      var max = 0;
      for (var prop in domains) {
        if (domains.hasOwnProperty(prop)) {
          max = max + 1;
        }
      }
      progressmeter.setAttribute("max", max);
      var label = document.getElementById("max");
      label.setAttribute("value", max);
      for (var prop in domains) {
        if (domains.hasOwnProperty(prop)) {
          //DoIhaveAnOpenID._logMessage("domains=" + prop);
          try {
            DoIhaveAnOpenID.getYadis(document, prop);
          } catch(e) {
            Components.utils.reportError(e);
          }
        }
      }
    } catch(e) {
      Components.utils.reportError(e);
    }
  }
    

};

